package core

import (
	"flag"
	"fmt"
	"github.com/APP/core/internal"
	"github.com/APP/global"
	"github.com/fsnotify/fsnotify"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"os"
)

// Viper 配置函数，返回配置对象 *viper.Viper
func Viper() *viper.Viper {
	// 获取配置文件路径（自定义函数，通常根据环境或命令行参数获取路径）
	config := getConfigPath()

	// 创建一个新的 Viper 实例
	v := viper.New()

	// 设置配置文件的完整路径
	v.SetConfigFile(config)

	// 设置配置文件类型为 yaml
	v.SetConfigType("yaml")

	// 读取配置文件
	err := v.ReadInConfig()
	if err != nil {
		// 如果读取失败，抛出错误并终止程序
		panic(fmt.Errorf("fatal error config file: %w", err))
	}

	// 启用配置文件热更新（监听文件变动）
	v.WatchConfig()

	// 当配置文件变动时触发的回调函数
	v.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("config file changed:", e.Name)

		// 将变更后的配置反序列化到全局配置结构体中
		if err = v.Unmarshal(&global.APP_CONFIG); err != nil {
			// 打印反序列化错误
			fmt.Println(err)
		}
	})

	// 初始化时也将配置反序列化进结构体
	if err = v.Unmarshal(&global.APP_CONFIG); err != nil {
		// 反序列化失败则抛出致命错误
		panic(fmt.Errorf("fatal error unmarshal config: %w", err))
	}

	// 设置根目录路径（适配代码生成器路径等）
	// filepath.Abs("..") 获取当前路径的上一级绝对路径
	//global.APP_CONFIG.AutoCode.Root, _ = filepath.Abs("..")

	// 返回配置对象
	return v
}

// getConfigPath 获取配置文件路径，优先级顺序如下：
// 1. 命令行参数（-c）
// 2. 环境变量 GVA_CONFIG
// 3. 根据 gin 模式选择对应配置文件（debug/release/test）
// 4. 如果路径无效，使用默认配置文件路径
func getConfigPath() (config string) {
	// 定义一个命令行参数 -c，用于指定配置文件路径，将其赋值到 config 变量中
	flag.StringVar(&config, "c", "", "choose config file.")
	// 解析命令行参数
	flag.Parse()

	// 如果命令行参数中指定了 -c，则优先使用该配置文件路径
	if config != "" {
		fmt.Printf("您正在使用命令行的 '-c' 参数传递的值, config 的路径为 %s\n", config)
		return // 直接返回该路径
	}

	// 如果没有指定 -c 参数，则尝试从环境变量中读取配置文件路径
	if env := os.Getenv(internal.ConfigEnv); env != "" {
		config = env
		fmt.Printf("您正在使用 %s 环境变量, config 的路径为 %s\n", internal.ConfigEnv, config)
		return // 返回从环境变量中获取的路径
	}

	// 如果命令行参数和环境变量都没有提供配置路径，
	// 则根据 gin 当前运行模式选择默认的配置文件名
	switch gin.Mode() {
	case gin.DebugMode:
		config = internal.ConfigDebugFile // 调试模式使用 debug 配置
	case gin.ReleaseMode:
		config = internal.ConfigReleaseFile // 生产模式使用 release 配置
	case gin.TestMode:
		config = internal.ConfigTestFile // 测试模式使用 test 配置
	}

	// 打印当前使用的 gin 模式及对应的配置文件路径
	fmt.Printf("您正在使用 gin 的 %s 模式运行, config 的路径为 %s\n", gin.Mode(), config)

	// 检查该配置文件路径是否实际存在
	_, err := os.Stat(config)
	if err != nil || os.IsNotExist(err) {
		// 如果文件不存在或路径无效，则使用默认的配置文件路径
		config = internal.ConfigDefaultFile
		fmt.Printf("配置文件路径不存在, 使用默认配置文件路径: %s\n", config)
	}

	// 返回最终确定的配置文件路径
	return
}
